//********************************************************************************************************
// Product Name: MapWindow.dll Alpha
// Description:  The basic module for MapWindow version 6.0
//********************************************************************************************************
// The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); 
// you may not use this file except in compliance with the License. You may obtain a copy of the License at 
// http://www.mozilla.org/MPL/ 
//
// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF 
// ANY KIND, either expressed or implied. See the License for the specificlanguage governing rights and 
// limitations under the License. 
//
// The Original Code is from MapWindow.dll version 6.0
//
// The Initial Developer of this Original Code is Ted Dunsford. Created 6/26/2008 7:35:12 AM
// 
// Contributor(s): (Open source contributors should list themselves and their modifications here). 
//
//********************************************************************************************************

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;

using Microsoft.DirectX.Direct3D;
using Microsoft.DirectX;

using MapWindow.Drawing;
using MapWindow.Geometries;

namespace MapWindow.DirectX
{


    /// <summary>
    /// ColoredCircleList
    /// </summary>
    public class PrimitiveBaseDX : RenderBaseDX
    {
        #region Private Variables

        private VertexCollection _vertices;
        private IndexCollection _indices;
        private PrimitiveType _primitiveType;
        private ScaleModes _scaleMode;
        private float _previousScale;
        private float _resizeFactor = 2;
        private TextureComponent _texture;
        private int _numPrimitivesToDraw=-1;

        #endregion

        #region Constructors

        /// <summary>
        /// By default, this assumes you will be creating a triangle list and that the
        /// type of vertices will be textured.
        /// </summary>
        public PrimitiveBaseDX()
        {
            ConfigureTexture();
        }

        /// <summary>
        /// A Colored, Indexed Base List is defined as having a PositionColored vertex collection,
        /// and uses index values in order to control how to organize the layers.
        /// </summary>
        /// <param name="inColor">Specifies the color for this Base</param>
        public PrimitiveBaseDX(Color inColor)
        {
            ConfigureColor(PrimitiveType.TriangleList, inColor);
        }

       


        /// <summary>
        /// A Colored, Indexed Base List is defined as having a PositionColored vertex collection,
        /// and uses index values in order to control how to organize the layers.
        /// </summary>
        /// <param name="inPrimitiveType">Specifies the PrimitiveType for this Base</param>
        /// <param name="inColor">Specifies the color</param>
        public PrimitiveBaseDX(PrimitiveType inPrimitiveType, Color inColor)
        {
            ConfigureColor(inPrimitiveType, inColor);
        }

       
        private void ConfigureColor(PrimitiveType inPrimitiveType, Color inColor)
        {
            _indices = new IndexCollection();
            _vertices = new PositionColoredVC(inColor);
            _primitiveType = inPrimitiveType;
            _scaleMode = ScaleModes.Geographic;
        }

        private void ConfigureTexture()
        {
            _indices = new IndexCollection();
            _vertices = new PositionTexturedVC();
            _texture = new TextureComponent();
            _primitiveType = PrimitiveType.TriangleList;
            _scaleMode = ScaleModes.Geographic;
        }
       

        #endregion

        #region Methods

       

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets the color to use when creating the caps.
        /// </summary>
        public Color Color
        {
            get 
            {
                PositionColoredVC pc = _vertices as PositionColoredVC;
                if (pc == null) return Color.Empty;
                return pc.Color;
            }
            set 
            {
                if (_vertices == null)
                {
                    _vertices = new PositionColoredVC(value);
                    return;
                }
                PositionColoredVC pc = _vertices as PositionColoredVC;
                if (pc == null)
                {
                    throw new InvalidOperationException("Color cannot be specified for a textured primitive type.");
                }
                pc.Color = value;
            }
        }

        /// <summary>
        /// Gets or sets the number of primitives to draw.  This is normally calculated
        /// from the 
        /// </summary>
        public virtual int NumPrimitivesToDraw
        {
            get
            {
                if (_numPrimitivesToDraw != -1) return _numPrimitivesToDraw;
                
                int numVertices = _vertices.NumVerticesToDraw;
                
                if (_indices != null && _indices.Count > 0)
                {
                    numVertices = _indices.Count - _indices.StartIndex;
                }
               
                switch (_primitiveType)
                {
                    case PrimitiveType.PointList: return numVertices;
                    case PrimitiveType.LineList: return numVertices / 2;
                    case PrimitiveType.TriangleList: return numVertices / 3;
                    default:
                        throw new NotSupportedException("The NumPrimitivesToDraw method could not be calculated for this primitive type.");
                }
 
                
            }
            set
            {
                if (value < -1) _numPrimitivesToDraw = -1;
                
                _numPrimitivesToDraw = value;
            }
        }

        ///// <summary>
        ///// Occurs when this member is being initialized and fires the Initialized event.
        ///// </summary>
        ///// <param name="sender"></param>
        ///// <param name="e"></param>
        //protected override void OnInitialize(object sender, DrawArgsDX e)
        //{
            
        //    base.OnInitialize(sender, e);
        //}

    

        /// <summary>
        /// Gets or sets the IndexCollection being used to specify when to draw each vertex
        /// </summary>
        public virtual IndexCollection Indices
        {
            get { return _indices; }
            set 
            { 
                _indices = value;
            }
        }

        /// <summary>
        /// Gets a boolean that is true if the index collection is not null.
        /// </summary>
        public virtual bool IsIndexed
        {
            get { return (_indices != null); }
        }

        /// <summary>
        /// Gets or sets
        /// </summary>
        public virtual bool IsTextured
        {
            get { return (_texture != null); }
           
        }

        /// <summary>
        /// Gets or sets the current drawbox being used by the vertices to turn double precision
        /// coordinates into the float coordinates required by directX without losing accuracy.
        /// </summary>
        public DrawBox DrawBox
        {
            get { return _vertices.DrawBox; }
            set { _vertices.DrawBox = value; }
        }

        /// <summary>
        /// Gets or sets the VertexCollection being used to control the actual vertices
        /// </summary>
        public virtual VertexCollection Vertices
        {
            get { return _vertices; }
            set { _vertices = value; }
        }

        /// <summary>
        /// Gets the scale mode
        /// </summary>
        public virtual ScaleModes ScaleMode
        {
            get { return _scaleMode; }
            set { _scaleMode = value; }
        }

        /// <summary>
        /// Gets the primitive Type
        /// </summary>
        public virtual PrimitiveType PrimitiveType
        {
            get { return _primitiveType; }
            set { _primitiveType = value; }
        }

        /// <summary>
        /// Returns the Previous Scale
        /// </summary>
        public float PreviousScale
        {
            get { return _previousScale; }
            protected set { _previousScale = value; }
        }

        /// <summary>
        /// When zooming out, if the geographic size of a single pixel is greater than or equal to the previous
        /// scale for this structure multiplied by the resize factor, then the image will be redrawn.  This
        /// factor works in both directions, so if the map is zoomed in, it uses the reciprocal of this factor.
        /// This value defaults to 2.
        /// </summary>
        public float ResizeFactor
        {
            get { return _resizeFactor; }
            set { _resizeFactor = value; }
        }

        /// <summary>
        /// Gets or sets the texture component
        /// </summary>
        public TextureComponent TextureComp
        {
            get { return _texture; }
            set { _texture = value; }
        }

        #endregion

        #region Protected Methods

        /// <summary>
        /// Disposes 
        /// </summary>
        protected override void Dispose(bool disposing)
        {
            //if (disposing && components != null)
            //{
            //    components.Dispose();
            //}
            if (_vertices != null) _vertices.Dispose();
            if (_indices != null) _indices.Dispose();
            if (_texture != null) _texture.Dispose();
        }

        /// <summary>
        /// This is the internal drawing method that follows the standard checks.  Drawing is evoked
        /// through the Draw3D command, but internally implemented in the DrawPart method.  After
        /// the initial checks, the Draw3D method will cycle the part integer from 0 to NumParts -1.
        /// </summary>
        /// <param name="args">A DrawArgsDX class with the device and camera.</param>
        protected override void OnDraw(DrawArgsDX args)
        {
            // If we are in Pixel Mode, check to see if the scale has changed, and initialize if it has
            if (_scaleMode == ScaleModes.Symbolic)
            {
                float scale = GetScale(args);

                if (scale < _previousScale / _resizeFactor || scale > _resizeFactor * _previousScale)
                {
                    Initialize(args);
                    _previousScale = scale;
                }
            }

            // Drawing Setup
            if (_indices != null && _indices.Count > 0) _indices.BeforeDrawing(args.Device);
            _vertices.BeforeDrawing(args.Device);
            if (_texture != null) _texture.BeforeDrawing(args.Device);


            // Actual Rendering
            if (_indices != null && _indices.Count > 0)
            {
                args.Device.DrawIndexedPrimitives(_primitiveType, _indices.BufferOffset, _vertices.StartVertex, _vertices.NumVerticesToDraw, _indices.StartIndex, NumPrimitivesToDraw);
            }
            else
            {
                args.Device.DrawPrimitives(_primitiveType, _vertices.StartVertex, NumPrimitivesToDraw);
            }

            // Reset Device
            if(_indices != null && _indices.Count > 0) _indices.AfterDrawing(args.Device);
            _vertices.AfterDrawing(args.Device);
            if (_texture != null) _texture.AfterDrawing(args.Device);

        }

        /// <summary>
        /// We assume that the index buffer is ok, since mainly we need to regenerate symbology
        /// or positions.  The vertices will be invalidated.
        /// </summary>
        /// <param name="e">An EventArgs parameter</param>
        protected override void OnInvalidate(EventArgs e)
        {
            if (_indices != null && _indices.Count > 0) _indices.Invalidate();
            if (_vertices != null) _vertices.Invalidate();
            //_vertices.Invalidate();
            base.OnInvalidate(e);
        }

        #endregion

    }
}
